﻿/*=============================================================================
* File Name : Vector2.h                         Ver : 1.00  Date : 2009-3-15
*
* Description :
*
*       2Dベクトル計算　ヘッダ
*
* Author : 土田　悠貴.
*============================================================================*/
#include "Vector2.h"
#include "Vector3.h"
#include "Vector4.h"
#include "Math.h"
#include "Matrix3.h"

namespace tglib
{

/*===========================================================================*/
/**
 * コンストラクタ．
 */
Vector2::Vector2() : x( 0.0f ), y( 0.0f )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     X　X座標．
 * @param [in]     Y　Y座標．
 */
Vector2::Vector2( float X, float Y ) : x( X ), y( Y )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     v3　3Dベクトル．
 */
Vector2::Vector2( const Vector3& v3 ) : x( v3.x ), y( v3.y )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     v4　四次元ベクトル．
 */
Vector2::Vector2( const Vector4& v4 ) : x( v4.x ), y( v4.y )
{}

/*===========================================================================*/
/**
 * コンストラクタ．
 *
 * @param [in]     p　配列のポインタ．
 */
Vector2::Vector2( const float* p ) : x( p[0] ), y( p[1] )
{}
/*===========================================================================*/
/**
 * 正規化．
 */
Vector2& Vector2::normalize()
{
	float len;

	if( ( len = length() ) != 0 ){
		( *this ) /= len;
	}

	return *this;
}
/*===========================================================================*/
/**
 * 正規化したベクトルを取得する．
 *
 * @return 正規化したベクトル．
 */
Vector2 Vector2::getNormalized() const
{
	Vector2 result( *this );

	return ( result.normalize() );
}

/*===========================================================================*/
/**
 * 長さを求める．
 *
 * @return 長さ ．
 */
float Vector2::length() const
{
	return Math::Sqrt( lengthSq() );
}

/*===========================================================================*/
/**
 * 長さを求める (２乗和のみ）．
 *
 * @return 長さ(２乗和）．
 */
float Vector2::lengthSq() const
{
	return ( x * x + y * y );
}

/*===========================================================================*/
/**
 * 距離を求める．
 *
 * @param [in]  V 2Dベクトル ．
 * @return 距離 ．
 */
float Vector2::distance( const Vector2& V ) const
{
	Vector2 result;

	result = *this - V;

	return ( result.length() );
}

/*===========================================================================*/
/**
 * 内積を求める．
 *
 * @param [in]  name 2Dベクトル ．
 * @return 内積 ．
 */
float Vector2::dot( const Vector2& V ) const
{
	return ( x * V.x + y * V.y );
}

/*===========================================================================*/
/**
 * 外積を求める．
 *
 * @param [in]  V 2Dベクトル ．
 * @return 外積 ．
 */
float Vector2::CCW( const Vector2& V ) const
{
	return ( x * V.y - y * V.x );
}

/*===========================================================================*/
/**
 * 小さい要素を求める．
 *
 * @param [in]  V 2Dベクトル ．
 * @return 小さい要素 ．
 */
Vector2 Vector2::minimize( const Vector2& V ) const
{
	Vector2 result;

	result.x = Math::MIN( x, V.x );
	result.y = Math::MIN( y, V.y );

	return result;
}

/*===========================================================================*/
/**
 * 大きい要素を求める．
 *
 * @param [in]  V 2Dベクトル ．
 * @return 大きい要素 ．
 */
Vector2 Vector2::maximize( const Vector2& V ) const
{
	Vector2 result;

	result.x = Math::MAX( x, V.x );
	result.y = Math::MAX( y, V.y );

	return result;
}

/*===========================================================================*/
/**
 * 線形補間を行う．
 *
 * @param [in]  min 最小値．
 * @param [in]  max 最大値．
 * @param [in]  t 補間地(0.0～1.0) ．
 * @return 補間した2Dベクトル ．
 */
Vector2& Vector2::lerp( const Vector2& min, const Vector2& max, float t )
{
	x = Math::LERP( t, min.x, max.x );
	y = Math::LERP( t, min.y, max.y );

	return *this;
}

/*===========================================================================*/
/**
 * 二次補間を行う．
 *
 * @param [in]  v1 補間要素2Dベクトル.
 * @param [in]  v2 補間要素2Dベクトル.
 * @param [in]  v3 2Dベクトル.
 * @param [in]  t 補間値( 0.0f～1.0f ).
 * @return 補間した2Dベクトル ．
 */
Vector2& Vector2::quadratic( const Vector2& v1, const Vector2& v2, const Vector2& v3, float t )
{
	x = Math::QUADRATIC( t, v1.x, v2.x, v3.x );
	y = Math::QUADRATIC( t, v1.y, v2.y, v3.y );

	return *this;
}

/*===========================================================================*/
/**
 * 反射ベクトルを求める ．
 *
 * @param [in]  N 法線ベクトル ．
 * @return 反射ベクトル ．
 */
Vector2 Vector2::reflect( const Vector2& N ) const
{
	Vector2 result;

	Vector2 v( -(*this) );
	
	Vector2 t( N * ( v.dot( N ) * 2.0f ) );

	result = t + *this;

	return result;
}

/*===========================================================================*/
/**
 * 屈折ベクトルを求める．
 *
 * @param [in]  N 　法線ベクトル ．
 * @param [in]  Eta 屈折比率 ．
 * @return 屈折ベクトル ．
 */
Vector2 Vector2::refract( const Vector2& N, float Eta	) const
{
	Vector2 result;

	Vector2 T1( -(*this) );
	float cosI  = T1.dot( N );
	float cosT2 = 1.0f - Eta * Eta * ( 1.0f - cosI * cosI );

	if ( cosT2 <= 0.0f ){
		result.x = 0.0f;
		result.y = 0.0f;
	} else {
		T1 = ( *this ) * Eta;
		Vector2 T2( N * ( Eta * cosI - Math::Sqrt( Math::ABS( cosT2 ) ) ) );
		result = T1 + T2;
	}

	return	result;
}

/*===========================================================================*/
/**
 * ２つベクトルのなす角度を求める．
 *
 * @param [in]  V　2Dベクトル ．
 * @return 角度 ．
 */
float Vector2::degree( const Vector2& V ) const
{
	float cos_theta = ( dot( V ) / ( length() * V.length() ) );

	float angle = Math::Acos( Math::CLAMP( cos_theta, -1.0f, 1.0f ) );

	return angle;
}

/*===========================================================================*/
/**
 * 方位角を求める．
 *
 * @return 方位角 ．
 */
float Vector2::getDirection() const
{
	float len;

	// ベクトルの長さを求める
	if( ( len = length() ) == 0 ){
		// 長さが0の場合は0にする
		return 0.0f;
	}

	//　ベクトルの正規化をする
	float X = x / len;
	float Y = y / len;

	//　方位角の計算を行う
	return Math::Atan( X, Y );
}
/*===========================================================================*/
/**
 * 方位角からベクトルを求める．
 *
 * @param [in]  direction 引数の説明 ．
 * @return 2Dベクトル．
 */
Vector2& Vector2::fromDirection( float direction )
{
	x = Math::Sin( direction );
	y = Math::Cos( direction );

	return *this;
}

/*===========================================================================*/
/**
 * (float*型)キャスト演算子オーバーロード．
 *
 * @return   型変換をしたXY成分．
 */
Vector2::operator float* ()
{
	return reinterpret_cast<float*>( XY );
}

/*===========================================================================*/
/**
 * (const float*型)キャスト演算子オーバーロード．
 *
 * @return   型変換をしたXY成分．
 */
Vector2::operator const float* ()
{
	return reinterpret_cast<const float*>( XY );
}

/*===========================================================================*/
/**
 * (+)単項演算子オーバーロード．
 *
 * @return 結果のVector2．
 */
Vector2  Vector2::operator + () const
{
	return *this; 
}

/*===========================================================================*/
/**
 * (-)単項演算子オーバーロード．
 *
 * @return 結果のVector2.
 */
Vector2  Vector2::operator - () const
{
	return Vector2( -x, -y );
}

/*===========================================================================*/
/**
 * (+=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator += ( const Vector2& v )
{
	x = x + v.x;
	y = y + v.y;

	return *this;
}

/*===========================================================================*/
/**
 * (-=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator -= ( const Vector2& v )
{
	x = x - v.x;
	y = y - v.y;

	return *this;
}

/*===========================================================================*/
/**
 * (*=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator *= ( const Vector2& v )
{
	x = x * v.x;
	y = y * v.y;

	return *this;
}

/*===========================================================================*/
/**
 * (/=) 演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator /= ( const Vector2& v )
{
	x = x / v.x;
	y = y / v.y;

	return *this;
}

/*===========================================================================*/
/**
 * (*=) 演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator *= ( float s )
{
	x = x * s;
	y = y * s;

	return *this;
}

/*===========================================================================*/
/**
 * (/=) 演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @return 結果のVector2．
 */
Vector2&  Vector2::operator /= ( float s )
{
	x = x / s;
	y = y / s;

	return *this;
}

/***  以下非メンバ関数 *******************************************************/

/*===========================================================================*/
/**
 * (+)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator + ( const Vector2& v1, const Vector2& v2 )
{
	Vector2 result( v1 );

	result += v2; 

	return result;
}

/*===========================================================================*/
/**
 * (-)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator - ( const Vector2& v1, const Vector2& v2 )
{
	Vector2 result( v1 );

	result -= v2;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator * ( const Vector2& v1, const Vector2& v2 )
{
	Vector2 result( v1 );

	result *= v2;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @param [in]  s スカラー．
 * @return 結果のVector2．
 */
const Vector2 operator * ( const Vector2& v, const float s )
{
	Vector2 result( v );

	result *= s;

	return result;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator * ( const float s, const Vector2& v )
{
	return v * s;
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード(座標変換)．
 * 
 * @param [in]  m Matrix3．
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator * ( const Matrix3& m, const Vector2& v )
{
	return Vector2( v.x * m.m[0][0] + v.y * m.m[1][0] + m.m[2][0],
					v.x * m.m[0][1] + v.y * m.m[1][1] + m.m[2][1] );
}

/*===========================================================================*/
/**
 * (*)演算子オーバーロード(座標変換)．
 * 
 * @param [in]  v Vector2．
 * @param [in]  m Matrix3．
 * @return 結果のVector2．
 */
const Vector2 operator * ( const Vector2& v, const Matrix3& m )
{
	return Vector2( v.x * m.m[0][0] + v.y * m.m[0][1] + m.m[0][2],
					v.x * m.m[1][0] + v.y * m.m[1][1] + m.m[1][2] );
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator / ( const Vector2& v1, const Vector2& v2 )
{
	Vector2	result( v1 );

	result /= v2;

	return result;
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  v Vector2．
 * @param [in]  s スカラー．
 * @return 結果のVector2．
 */
const Vector2 operator / ( const Vector2& v, float s )
{
	Vector2 result( v );

	result /= s;

	return result;
}

/*===========================================================================*/
/**
 * (/)演算子オーバーロード．
 * 
 * @param [in]  s スカラー．
 * @param [in]  v Vector2．
 * @return 結果のVector2．
 */
const Vector2 operator / ( float s, const Vector2& v )
{
	return v / s;
}

/*===========================================================================*/
/**
 * (==) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator == ( const Vector2& v1, const Vector2& v2 )
{
	return ( v1.x == v2.x && v1.y == v2.y );
}

/*===========================================================================*/
/**
 * (!=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator != ( const Vector2& v1, const Vector2& v2 )
{
	return !( v1 == v2 );
}

/*===========================================================================*/
/**
 * (<) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator < ( const Vector2& v1, const Vector2& v2 )
{
	if( v1.x >= v2.x )
	{
		return false;
	}

	if( v1.y >= v2.y )
	{
		return false;
	}

	return true;
}

/*===========================================================================*/
/**
 * (>) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator > ( const Vector2& v1, const Vector2& v2 )
{
	if( v1.x <= v2.x ){
		return false;
	} 
	
	if( v1.y <= v2.y ){
		return false;
	}

	return true;
}

/*===========================================================================*/
/**
 * (<=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator <= ( const Vector2& v1, const Vector2& v2 )
{
	if( v1.x > v2.x )
	{
		return false;
	}

	if( v1.y > v2.y )
	{
		return false;
	}

	return true;
}

/*===========================================================================*/
/**
 * (>=) 演算子オーバーロード．
 * 
 * @param [in]  v1 Vector2．
 * @param [in]  v2 Vector2．
 * @return 比較結果．
 */
bool operator >= ( const Vector2& v1, const Vector2& v2 )
{
	if( v1.x < v2.x ){
		return false;
	} 
	
	if( v1.y < v2.y ){
		return false;
	}

	return true;
}

} // namespace tglib
/*========= End of File =====================================================*/
